package com.idroc.coelacanth.locate.support;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import com.idroc.coelacanth.locate.HashAlgorithm;

/**
 * hash算法 工厂
 * @author yuyoo (yuyoo4j@163.com)
 * @date Dec 10, 2009 10:41:52 PM
 */
public final class HashAlgorithms {

	/**
	 * java内置hash算法
	 */
	public static final HashAlgorithm JAVA_NATIVE_HASH = new JavaNativeHash();
	
	/**
	 * ketamahash算法,使用md5取最低4个字节作为int的hashcode
	 */
	public static final HashAlgorithm KETAMA_HASH = new KetamaHash();
	/**
	 * 一致性hash算法
	 */
	public static final HashAlgorithm CONSISTEND_HASH = new ConsistendHash();
	
	/**
	 * DJB hash 算法, 俗称'times33'hash算法
	 */
	public static final HashAlgorithm DJB_HASH = new DJBHash();
	
	/**
	 * 防止类被非法实例化
	 */
	private HashAlgorithms() {}
	
	public static class JavaNativeHash implements HashAlgorithm {

		public int hash(String key) {
			return key.hashCode();
		} 
	}
	
	public static class KetamaHash implements HashAlgorithm {
		
		private MessageDigest md5 = null;
		
		private KetamaHash() {
			try {
				md5 = MessageDigest.getInstance("MD5");
			} catch (NoSuchAlgorithmException e) {
				throw new RuntimeException("MD5 not supported", e);
			}
		}

		public int hash(final String key) {
 
			return hash(key.getBytes()); 
		} 
		
		public int hash(byte[] key) {
			
			md5.reset();
			md5.update(key);
			byte[] rtv = md5.digest();
			int h = ((rtv[3] & 0xFF) << 24)
					| ((rtv[2] & 0xFF)  << 16) 
					| ((rtv[1] & 0xFF)  << 8) 
					| (rtv[0] & 0xFF);
			return h;
		}
	}	
	
	public static class ConsistendHash implements HashAlgorithm {
		
		public static final int MAX_HASH = Integer.MAX_VALUE;
		public static final int MIN_HASH = 0;
		
		private final KetamaHash ketamaHash = new KetamaHash();

		public int hash(String key) {
			
			int hash = ketamaHash.hash(key);
			return Math.abs(hash);
		} 
		
		public int hash(byte[] key) {
			int hash = ketamaHash.hash(key);
			return Math.abs(hash);
		}
	}
	
	public static class DJBHash implements HashAlgorithm {

		public int hash(String key) {
			int hash = 5381;
			for (int i = 0; i < key.length(); i++) {
				hash = ((hash << 5) + hash) + key.charAt(i);
			}
			return hash;
		} 
	}
}
